package model;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import javax.swing.table.AbstractTableModel;

import domain.Book;
import domain.Copy;
import domain.Library;
import domain.Loan;

public class BookMasterTableModel extends AbstractTableModel implements Observer {
    private static BookMasterTableModel instance;
    private String[] columns = { "Verfügbar", "Titel", "Autor", "Verlag" };
    private List<Book> model;
    private final Library library;
    private static final long serialVersionUID = 2966279676059941187L;

    public static BookMasterTableModel getInstance() {
        if (instance == null)
            instance = new BookMasterTableModel();
        return instance;
    }

    private BookMasterTableModel() {
        library = Library.getInstance();
        library.addObserver(this);
        model = library.getBooks();
        this.fireTableDataChanged();
    }

    @Override
    public void update(Observable obj, Object arg1) {
        this.fireTableDataChanged();
        /*
        List<Book> modelOld = model;
        model = new ArrayList<>(library.getBooks());
        
        for(int o = 0, n = 0;; o++, n++) {
            Book currentBookOldModel = modelOld.get(o);
            Book currentBookNewModel = model.get(n);
            
            if(currentBookOldModel != currentBookNewModel) {
                if (!modelOld.contains(currentBookNewModel)) {
                    this.fireTableRowsInserted(n, n);
                    o--;
                } else if (!model.contains(currentBookOldModel)) {
                    this.fireTableRowsDeleted(n, n);
                    n--;
                } else {
                    this.fireTableRowsUpdated(n, n);
                }
            } else {
                this.fireTableRowsUpdated(n, n);
            }
            
            if(o+1 == modelOld.size() && n+1 == model.size())
                return;
                
            if(o+1 == modelOld.size()) {
                this.fireTableRowsInserted(n+1, model.size());
                return;
            } else if(n+1 == model.size()) {
                this.fireTableRowsDeleted(n+1, n + (modelOld.size() - model.size()));
                return;
            }
        }*/
        /*
        for (int i = 0; i < model.size(); i++) {
            if (!modelOld.contains(model.get(i))) {
                this.fireTableRowsInserted(i, i);
            }
        }
        for (int i = 0; i < modelOld.size(); i++) {
            if (!model.contains(modelOld.get(i))) {
                this.fireTableRowsDeleted(i, i);
            }
        }
        this.fireTableRowsInserted(firstRow, lastRow);
        this.fireTableDataChanged();*/
    }

    @Override
    public boolean isCellEditable(int arg0, int arg1) {
        return false;
    }

    @Override
    public String getColumnName(int column) {
        return columns[column];
    }

    @Override
    public int getColumnCount() {
        return columns.length;
    }

    @Override
    public int getRowCount() {
        return model.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Book book;
        book = model.get(rowIndex);
        switch (columnIndex) {
            case 0:
                return getAvailability(book);
            case 1:
                return book.getName();
            case 2:
                return book.getAuthor();
            case 3:
                return book.getPublisher();
            default:
                return null;
        }
    }

    private String getAvailability(Book book) {
        List<Copy> copies = library.getCopiesOfBook(book);
        DateFormat dateFormat = SimpleDateFormat.getDateInstance();
        GregorianCalendar availDate = new GregorianCalendar(9999, 12, 31);

        int availCount = 0;
        if (copies.size() > 0) {
            for (Copy copy : copies) {
                if (copy.isLent()) {
                    for (Loan loan : copy.getLoans()) {
                        if (availDate.compareTo(loan.getDueDate()) > 0) {
                            availDate = loan.getDueDate();
                        }
                    }
                } else {
                    availCount++;
                }
            }
            if (availCount > 0) {
                return Integer.toString(availCount);
            } else {
                return "ab " + dateFormat.format(availDate.getTime());
            }
        } else {
            return Integer.toString(0);
        }
    }

    public Book getElementAt(int rowIndex) {
        try {
            return model.get(rowIndex);
        } catch (ArrayIndexOutOfBoundsException e) {
            return null;
        }

    }

    @Override
    public Class<String> getColumnClass(int columnIndex) {
        return String.class;
    }

}
